#pragma once

#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <string>
#include <unordered_map>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
#include "jieba/Jieba.hpp"

namespace ns_util
{
    class FileUtil
    {
    public:
        static bool ReadFile(const std::string& path, std::string* file)
        {
            //打开文件流
            std::ifstream in(path, std::ios::in);
            if(!in.is_open()) {
                std::cerr << "open file " << path << " err" << std::endl;
                return false;
            }
            //每次获取一行数据，追加到file中
            std::string line;
            //getline的返回值是一个istream对象的引用，这个对象重载了强制类型转换
            while(std::getline(in, line)) {
                *file += line;
            }
            //关闭文件流
            in.close();
            return true;
        }

        static int getLineCount(const std::string& path)
        {
            std::ifstream file(path.c_str());
            // Number of lines in the file
            return std::count(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), '\n');
        }
    };

    class StringUtil
    {
    public:
        static void SplitString(std::vector<std::string>* result, const std::string& str, const std::string& sep)
        {
            boost::split(*result, str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
        }

        static std::string toLower(const std::string& str)
        {
            return boost::to_lower_copy(str);
        }
    };

    const char* const DICT_PATH = "./dict/jieba.dict.utf8";
    const char* const HMM_PATH = "./dict/hmm_model.utf8";
    const char* const USER_DICT_PATH = "./dict/user.dict.utf8";
    const char* const IDF_PATH = "./dict/idf.utf8";
    const char* const STOP_WORD_PATH = "./dict/stop_words.utf8";

    class JiebaUtil
    {
    public:
        static JiebaUtil* getInstance()
        {
            if(_instance == nullptr)
            {
                _lock.lock();
                if(_instance == nullptr)
                {
                    _instance = new JiebaUtil();
                    _instance->JiebaInit();
                }
                _lock.unlock();
            }
            return _instance;
        }

    public:
        static void CutString(const std::string& str, std::vector<std::string>* out)
        {
            JiebaUtil::getInstance()->CutStringHelper(str, out);
            
            // jieba.CutForSearch(str, *out);
        }
    
    private:
        bool JiebaInit()
        {
            std::ifstream in(STOP_WORD_PATH);
            if(!in.is_open()) { return false; }
            std::string pause;
            //读取暂停词至map
            while(std::getline(in, pause))
            {
                _pause_map.insert(std::make_pair(pause, true));
                pause.clear();
            }
            in.close();
            return true;
        }

        void CutStringHelper(const std::string& str, std::vector<std::string>* out)
        {
            std::vector<std::string> FirstCutVec;

            _jieba.CutForSearch(str, FirstCutVec);
            for(auto word : FirstCutVec) {
                if(!_pause_map[word]) { out->push_back(word); } //不是暂停词
            }
        }

    private:
        JiebaUtil()
            :_jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH)
        { };
        JiebaUtil(const JiebaUtil&) = delete;
        JiebaUtil& operator=(const JiebaUtil&) = delete;

    private:
        static JiebaUtil* _instance;
        static std::mutex _lock;

    private:
        cppjieba::Jieba _jieba;
        std::unordered_map<std::string, bool> _pause_map;
        // static cppjieba::Jieba jieba;
    };
    
    JiebaUtil* JiebaUtil::_instance = nullptr;
    std::mutex JiebaUtil::_lock;

    // cppjieba::Jieba JiebaUtil::jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH);
}
